/*
 * Copyright (c) www.bugull.com
 */

package com.bugull.farm.device.balancer;

import com.bugull.farm.core.cache.PropertiesCache;
import com.bugull.farm.core.codec.DefaultCryptoDecoder;
import com.bugull.farm.core.codec.DefaultCryptoEncoder;
import com.bugull.farm.core.factory.SslContextFactory;
import com.bugull.farm.core.frame.loader.PropertiesLoader;
import com.bugull.farm.core.frame.loader.XmlLoader;
import com.bugull.farm.core.handler.FarmIdleChannelHandler;
import com.bugull.farm.core.server.FarmServer;
import com.bugull.farm.core.server.ZKClient;
import com.bugull.farm.device.balancer.handler.DeviceChannelStatusHandler;
import com.bugull.farm.device.balancer.handler.MyDeviceFrameHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.io.File;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;

/**
 *
 * @author Frank Wen(xbwen@hotmail.com)
 */
public class DeviceBalancer extends FarmServer {
	private SSLContext sslCtx;    
    private void init(){
        
        //add shutdown hook
        this.addShutdownHook();
    }
    
    private void start() throws Exception {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        sslCtx = SslContextFactory.getServerContext();
        ChannelInitializer<SocketChannel> channelInit = new ChannelInitializer<SocketChannel>(){
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
              SSLEngine sslEngine = sslCtx.createSSLEngine();
        		sslEngine.setUseClientMode(false);
                ch.pipeline()
                        .addFirst(new DeviceChannelStatusHandler())
                        .addLast(new IdleStateHandler(0, 10, 0, TimeUnit.SECONDS))
                        .addLast(new FarmIdleChannelHandler())
                        .addLast(new SslHandler(sslEngine))
                        .addLast(new LengthFieldBasedFrameDecoder(256, 8, 2))
                        .addLast(new MyDeviceFrameHandler());
            }
        };
        b.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .option(ChannelOption.SO_BACKLOG, 1024)
            .childHandler(channelInit)
            .childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE);
        try{
            ChannelFuture f = b.bind(PropertiesCache.getInstance().getInt("dev.balancer.port")).sync();
            System.out.println("DeviceBalancer start listen on port " + PropertiesCache.getInstance().getInt("dev.balancer.port") + "......");
            f.channel().closeFuture().sync();
        }finally{
            this.doShutdown();
        }
    }
    
    public static void main(String[] args) throws Exception {
    	//加载配置文件
    	String path = System.getProperty("user.dir");
    	path = path.substring(0, path.lastIndexOf(File.separator) + 1);
    	String xmlPath = path + File.separator + "xml";
    	String propsPath = path + "properties.properties";
    	//加载通信协议模板文件
        XmlLoader xLoader = new XmlLoader();
        xLoader.load(xmlPath);
        //加载配置文件
        PropertiesLoader pLoader = new PropertiesLoader();
        pLoader.load(propsPath);
        
        ZKClient zkClient = ZKClient.getInstance();
        zkClient.connect(PropertiesCache.getInstance().get("zk.conn"));
        
        DeviceBalancer balancer = new DeviceBalancer();
        balancer.init();
        balancer.start();
    }

}
